/**************************************************************************************
*
*	Copyright (C) 2010 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	GraphicsResourceManager.h
*
*	Description -	Graphics resource management system.
*
*	Comments	-	
*
*	Modification History:
*			Name			   Date					Description
*			MrCodeSushi	-	10/25/2010	-	Creation of this file.
**************************************************************************************/

#ifndef _PSX_VERTEX_MANAGER_H_
#define _PSX_VERTEX_MANAGER_H_

#include "PulseSTD.h"
#include "ResourcePool.h"
#include "Singleton.h"
#include "GraphicsTypes.h"
#include "ResourceManager.h"
#include "Mutex.h"
#include "Buffer.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "ConstantBuffer.h"
#include "StructuredBuffer.h"
#include "Texture2D.h"
#include "SwapChain.h"
#include "DepthStencilState.h"
#include "BlendState.h"
#include "RasterizerState.h"
#include "VertexShader.h"
#include "HullShader.h"
#include "DomainShader.h"
#include "GeometryShader.h"
#include "PixelShader.h"
#include "ComputeShader.h"
#include "InputLayout.h"
#include "Geometry.h"
#include "Material.h"
#include "Effect.h"
#include "RenderTechnique.h"
#include "Model.h"

namespace Pulse
{

	class GraphicsResourceManager : public Singleton< GraphicsResourceManager >
	{
	public:

		virtual ~GraphicsResourceManager( void );

		// TODO: Add Create resources methods here
		Buffer * CreateBuffer( BufferDesc *pDesc );
		Buffer * CreateBuffer( const CHAR *pName, BufferDesc *pDesc );

		StructuredBuffer * CreateStructuredBuffer( StructuredBufferDesc *pDesc );
		StructuredBuffer * CreateStructuredBuffer( const CHAR *pName, StructuredBufferDesc *pDesc );

		VertexBuffer * CreateVertexBuffer( VertexBufferDesc *pDesc );
		VertexBuffer * CreateVertexBuffer( const CHAR *pName, VertexBufferDesc *pDesc );

		IndexBuffer * CreateIndexBuffer( IndexBufferDesc *pDesc );
		IndexBuffer * CreateIndexBuffer( const CHAR *pName, IndexBufferDesc *pDesc );

		Texture2D * CreateTexture2D( Texture2DDesc *pDesc );
		Texture2D * CreateTexture2D( const CHAR *pName, Texture2DDesc *pDesc );
	
		SwapChain * CreateSwapChain( SwapChainDesc *pDesc );
		SwapChain * CreateSwapChain( const CHAR *pName, SwapChainDesc *pDesc );
		
		DepthStencilState * CreateDepthStencilState( DepthStencilStateDesc *pDesc );
		DepthStencilState * CreateDepthStencilState( const CHAR *pName, DepthStencilStateDesc *pDesc );

		BlendState * CreateBlendState( BlendStateDesc *pDesc );
		BlendState * CreateBlendState( const CHAR *pName, BlendStateDesc *pDesc );

		RasterizerState * CreateRasterizerState( RasterizerStateDesc *pDesc );
		RasterizerState * CreateRasterizerState( const CHAR *pName, RasterizerStateDesc *pDesc );

		ConstantBuffer * CreateConstantBuffer( ConstantBufferDesc *pDesc );
		ConstantBuffer * CreateConstantBuffer( const CHAR *pName, ConstantBufferDesc *pDesc );

		VertexShader * CreateVertexShader( ShaderDesc *pDesc );
		VertexShader * CreateVertexShader( const CHAR *pName, ShaderDesc *pDesc );

		HullShader * CreateHullShader( ShaderDesc *pDesc );
		HullShader * CreateHullShader( const CHAR *pName, ShaderDesc *pDesc );

		DomainShader * CreateDomainShader( ShaderDesc *pDesc );
		DomainShader * CreateDomainShader( const CHAR *pName, ShaderDesc *pDesc );

		GeometryShader * CreateGeometryShader( ShaderDesc *pDesc );
		GeometryShader * CreateGeometryShader( const CHAR *pName, ShaderDesc *pDesc );

		PixelShader * CreatePixelShader(ShaderDesc *pDesc );
		PixelShader * CreatePixelShader( const CHAR *pName, ShaderDesc *pDesc );

		ComputeShader * CreateComputeShader( ShaderDesc *pDesc );
		ComputeShader * CreateComputeShader( const CHAR *pName, ShaderDesc *pDesc );
	
		InputLayout * CreateInputLayout( InputLayoutDesc *pDesc );
		InputLayout * CreateInputLayout( const CHAR *pName, InputLayoutDesc *pDesc );

		Geometry * CreateGeometry( GeometryDesc *pDesc );
		Geometry * CreateGeometry( const CHAR *pName, GeometryDesc *pDesc );

		Material * CreateMaterial( MaterialDesc *pDesc );
		Material * CreateMaterial( const CHAR *pName, MaterialDesc *pDesc );

		RenderTechnique * CreateRenderTechnique( RenderTechniqueDesc *pDesc );
		RenderTechnique * CreateRenderTechnique( const CHAR *pName, RenderTechniqueDesc *pDesc );

		Effect * CreateEffect( EffectDesc *pDesc );
		Effect * CreateEffect( const CHAR *pName, EffectDesc *pDesc );
		Effect * FindEffect( const CHAR *pName );

		Model * CreateModel( ModelDesc *pDesc );
		Model * CreateModel( const CHAR *pName, ModelDesc *pDesc );

	private:

		friend GraphicsDevice;

		GraphicsResourceManager( void );

		virtual EErrorCode::Type Initialize( void );

		virtual void Cleanup( void );

	private:
		
		friend Singleton;

		template < typename T >
		struct FactoryWrapper
		{

			void Initialize( SIZE_T growSize, ResourceCode regCode );

			void Cleanup( void );

			T * Create( BaseResDesc *pDesc );

			T * Create( const CHAR *pName, BaseResDesc *pDesc );

			T * Find( const CHAR *pName );
			
			//Mutex m_mutex; // ResourcePool now directly supports concurrent creation
			ResourcePool<T> m_factory;
			ResourceCode m_regCode;
		};

		FactoryWrapper<Buffer>				m_buffers;
		FactoryWrapper<StructuredBuffer>	m_structuredBuffers;
		FactoryWrapper<VertexBuffer>		m_vertexBuffers;
		FactoryWrapper<IndexBuffer>			m_indexBuffers;
		//ResourcePool< Texture2D >			m_2Dtextures;
		FactoryWrapper<Texture2D>			m_2DTextures;
		//ResourcePool< SwapChain >			m_swapChains;
		FactoryWrapper<SwapChain>			m_swapChains;
		FactoryWrapper<DepthStencilState>	m_depthStencilStates;
		FactoryWrapper<BlendState>			m_blendStates;
		FactoryWrapper<RasterizerState>		m_rasterizerStates;
		FactoryWrapper<ConstantBuffer>		m_constantBuffers;
		//ResourcePool< VertexShader >		m_vertexShaders;
		FactoryWrapper<VertexShader>		m_vertexShaders;
		//ResourcePool< HullShader >		m_hullShaders;
		FactoryWrapper<HullShader>			m_hullShaders;
		//ResourcePool< DomainShader >		m_domainShaders;
		FactoryWrapper<DomainShader>		m_domainShaders;
		//ResourcePool< GeometryShader >	m_geometryShaders;
		FactoryWrapper<GeometryShader>		m_geometryShaders;
		//ResourcePool< PixelShader >		m_pixelShaders;
		FactoryWrapper<PixelShader>			m_pixelShaders;
		//ResourcePool< ComputeShader >		m_computeShaders;
		FactoryWrapper<ComputeShader>		m_computeShaders;
		//ResourcePool< InputLayout >		m_inputLayouts;
		FactoryWrapper<InputLayout>			m_inputLayouts;
		FactoryWrapper<Geometry>			m_geometries;
		FactoryWrapper<Material>			m_materials;
		FactoryWrapper<RenderTechnique>		m_techniques;
		FactoryWrapper<Effect>				m_effects;
		FactoryWrapper<Model>				m_models;
	};

	template < typename T >
	void GraphicsResourceManager::FactoryWrapper<T>::Initialize( SIZE_T growSize, ResourceCode regCode )
	{
		m_regCode = regCode;
		m_factory.Create( growSize );
		m_factory.SetResourceCode( regCode );
		ResourceManager::GetInstance()->RegisterResourcePool( &m_factory, regCode );
	}

	template < typename T >
	void GraphicsResourceManager::FactoryWrapper<T>::Cleanup( void )
	{
		ResourceManager::GetInstance()->UnregisterResourcePool( m_regCode );
	}

	template < typename T >
	PSX_FORCE_INLINE T * GraphicsResourceManager::FactoryWrapper<T>::Create( BaseResDesc *pDesc )
	{
		return m_factory.CreateResource( pDesc );
	}

	template < typename T >
	PSX_FORCE_INLINE T * GraphicsResourceManager::FactoryWrapper<T>::Create( const CHAR *pName, BaseResDesc *pDesc )
	{
		// Resource pool is now naturally lock safe.
		//MutexLocker lock( m_mutex );
		return m_factory.CreateResource( pName, pDesc );
	}

	template < typename T >
	PSX_FORCE_INLINE T * GraphicsResourceManager::FactoryWrapper<T>::Find( const CHAR *pName )
	{
		return m_factory.FindResource( &String(pName) );
	}

}

#endif /* _PSX_VERTEX_BUFFER_MANAGER_H_ */